-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[CIR] Support ComplexType in CallExpr args #156236
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[CIR] Support ComplexType in CallExpr args #156236
Conversation
|
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clangir Author: Amr Hesham (AmrDeveloper) ChangesThis change adds support for ComplexType in the CallExpr arg Issue: #141365 Full diff: https://github.com/llvm/llvm-project/pull/156236.diff 3 Files Affected:
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 25859885296fa..d0e0a66df904b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -15,6 +15,7 @@
#include "CIRGenCXXABI.h"
#include "CIRGenFunction.h"
#include "CIRGenFunctionInfo.h"
+#include "mlir/IR/Location.h"
#include "clang/CIR/MissingFeatures.h"
using namespace clang;
@@ -518,7 +519,8 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
assert(!cir::MissingFeatures::opCallPaddingArgs());
mlir::Type argType = convertType(canQualArgType);
- if (!mlir::isa<cir::RecordType>(argType)) {
+ if (!mlir::isa<cir::RecordType>(argType) &&
+ !mlir::isa<cir::ComplexType>(argType)) {
mlir::Value v;
if (arg.isAggregate())
cgm.errorNYI(loc, "emitCall: aggregate call argument");
@@ -536,15 +538,16 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
cirCallArgs[argNo] = v;
} else {
Address src = Address::invalid();
- if (!arg.isAggregate())
- cgm.errorNYI(loc, "emitCall: non-aggregate call argument");
- else
+ if (!arg.isAggregate()) {
+ src = createMemTemp(arg.ty, loc, "coerce");
+ arg.copyInto(*this, src, loc);
+ } else {
src = arg.hasLValue() ? arg.getKnownLValue().getAddress()
: arg.getKnownRValue().getAggregateAddress();
+ }
// Fast-isel and the optimizer generally like scalar values better than
// FCAs, so we flatten them if this is safe to do for this argument.
- auto argRecordTy = cast<cir::RecordType>(argType);
mlir::Type srcTy = src.getElementType();
// FIXME(cir): get proper location for each argument.
mlir::Location argLoc = loc;
@@ -560,7 +563,7 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
// uint64_t DstSize = CGM.getDataLayout().getTypeAllocSize(STy);
// if (SrcSize < DstSize) {
assert(!cir::MissingFeatures::dataLayoutTypeAllocSize());
- if (srcTy != argRecordTy) {
+ if (srcTy != argType) {
cgm.errorNYI(loc, "emitCall: source type does not match argument type");
} else {
// FIXME(cir): this currently only runs when the types are exactly the
@@ -672,6 +675,18 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
llvm_unreachable("Invalid evaluation kind");
}
+void CallArg::copyInto(CIRGenFunction &cgf, Address addr,
+ mlir::Location loc) const {
+ LValue dst = cgf.makeAddrLValue(addr, ty);
+ if (!hasLV && rv.isScalar())
+ cgf.cgm.errorNYI(loc, "copyInto scalar value");
+ else if (!hasLV && rv.isComplex())
+ cgf.emitStoreOfComplex(loc, rv.getComplexValue(), dst, /*isInit=*/true);
+ else
+ cgf.cgm.errorNYI(loc, "copyInto hasLV");
+ isUsed = true;
+}
+
void CIRGenFunction::emitCallArg(CallArgList &args, const clang::Expr *e,
clang::QualType argType) {
assert(argType->isReferenceType() == e->isGLValue() &&
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.h b/clang/lib/CIR/CodeGen/CIRGenCall.h
index 81cbb854f3b7d..994d960e3f17f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.h
@@ -15,6 +15,7 @@
#define CLANG_LIB_CODEGEN_CIRGENCALL_H
#include "CIRGenValue.h"
+#include "mlir/IR/Location.h"
#include "mlir/IR/Operation.h"
#include "clang/AST/GlobalDecl.h"
#include "llvm/ADT/SmallVector.h"
@@ -224,6 +225,8 @@ struct CallArg {
}
bool isAggregate() const { return hasLV || rv.isAggregate(); }
+
+ void copyInto(CIRGenFunction &cgf, Address addr, mlir::Location loc) const;
};
class CallArgList : public llvm::SmallVector<CallArg, 8> {
diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp
index e435a5e6ed010..d0a42276ef38e 100644
--- a/clang/test/CIR/CodeGen/complex.cpp
+++ b/clang/test/CIR/CodeGen/complex.cpp
@@ -853,3 +853,46 @@ void foo32() {
// OGCG: %[[REAL_ADDR:.*]] = alloca i32, align 4
// OGCG: %[[REAL:.*]] = load i32, ptr @_ZN9Container1cE, align 4
// OGCG: store i32 %[[REAL]], ptr %[[REAL_ADDR]], align 4
+
+void foo33(float _Complex a) {}
+
+// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a", init]
+// CIR: cir.store %{{.*}}, %[[A_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
+
+// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM: store { float, float } %{{.*}}, ptr %[[A_ADDR]], align 4
+
+// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG: store <2 x float> %a.coerce, ptr %[[A_ADDR]], align 4
+
+void foo34() {
+ float _Complex a;
+ foo33(a);
+}
+
+// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"]
+// CIR: %[[ARG_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["coerce"]
+// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR: cir.store{{.*}} %[[TMP_A]], %[[ARG_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>
+// CIR: %[[TMP_ARG:.*]] = cir.load{{.*}} %[[ARG_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float>
+// CIR: cir.call @_Z5foo33Cf(%[[TMP_ARG]]) : (!cir.complex<!cir.float>) -> ()
+
+// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM: %[[ARG_ADDR:.*]] = alloca { float, float }, i64 1, align 4
+// LLVM: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4
+// LLVM: store { float, float } %[[TMP_A]], ptr %[[ARG_ADDR]], align 4
+// LLVM: %[[TMP_ARG:.*]] = load { float, float }, ptr %[[ARG_ADDR]], align 4
+// LLVM: call void @_Z5foo33Cf({ float, float } %[[TMP_ARG]])
+
+// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG: %[[ARG_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0
+// OGCG: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4
+// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1
+// OGCG: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4
+// OGCG: %[[ARG_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[ARG_ADDR]], i32 0, i32 0
+// OGCG: %[[ARG_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[ARG_ADDR]], i32 0, i32 1
+// OGCG: store float %[[A_REAL]], ptr %[[ARG_REAL_PTR]], align 4
+// OGCG: store float %[[A_IMAG]], ptr %[[ARG_IMAG_PTR]], align 4
+// OGCG: %[[TMP_ARG:.*]] = load <2 x float>, ptr %[[ARG_ADDR]], align 4
+// OGCG: call void @_Z5foo33Cf(<2 x float> noundef %[[TMP_ARG]])
|
6f5711f to
b823f59
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
| // CIR: cir.store %{{.*}}, %[[A_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>> | ||
|
|
||
| // LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4 | ||
| // LLVM: store { float, float } %{{.*}}, ptr %[[A_ADDR]], align 4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems different from OG, probably ABI related since we don't have call conv lowering yet? Wonder how we should document this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can add a TODO(cir) with a small description in the test that should be updated once CallConvLowering is finished but not sure if there is a place where we can add missing feature or full description 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without calling convention lowering, any complex arguments are likely to be wrong. I'm not sure there's any value in lowering such arguments to LLVM IR before we've handled the calling convention part. Is there any way we can detect that and emit an error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any way we can detect that and emit an error?
For now, we can detect if any parameter type is a complex type in CIRGenFunction::startFunction to report error NYI, and we can delay call expr with complex until we start call conv lowering 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I think it's useful to lower "wrong" and check it because it will be in obvious contrast with the OGCG counterpart. Once callconv implementation starts this test will fail for complex, so it's easier to come and change for the correct one to match OG.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, we should note this fact in the comment thought.
801bda2 to
6d47596
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM pending the addition of a comment in the tests!
6d47596 to
59ef384
Compare
This change adds support for ComplexType in the CallExpr args Issue: llvm#141365
This change adds support for ComplexType in the CallExpr arg
Issue: #141365